#include <iostream>
#include "algo.h"
#include "iterator.h"
#include <vector>
#include "vector.h"

template <class T>
void display(T x)
{
    for(auto it = x.begin(); it != x.end(); it++)
        std::cout << *it << " ";
    std::cout << std::endl;
}

template <class T>
void print(T x)
{
    std::cout << x << " ";
}

template <class T>
bool uni_operator_bool(T x)
{
    return x % 2;
}

void algo_test()
{
    using namespace std;

    std::cout << "************************test remove_copy************************" << std::endl;
    mystl::vector<int> remove_copy_test = {1, 2, 3, 4, 3, 5, 6, 7, 4, 3, 8, 3};
    mystl::vector<int> remove_copy_result;
    remove_copy_result.resize(remove_copy_test.size());
    mystl::remove_copy(remove_copy_test.begin(), remove_copy_test.end(),
                        remove_copy_result.begin(), (vector<int>::value_type)(3));
    display<mystl::vector<int>>(remove_copy_result);

    std::cout << "************************test remove************************" << std::endl;
    vector<int> remove_test = {1, 2, 3, 4, 3, 5, 6, 7, 4, 7, 8, 3};
    vector<int>::iterator remove_last =  mystl::remove(
        remove_test.begin(), remove_test.end(), (vector<int>::value_type)(3));
    mystl::for_each(remove_test.begin(), remove_last, print<vector<int>::value_type>);
    cout << endl;

    std::cout << "************************test remove_copy_if************************" << std::endl;
    vector<int> remove_copy_if_test = {1, 2, 3, 4, 3, 5, 6, 7, 4, 3, 8, 3};
    vector<int> remove_copy_if_result;
    remove_copy_if_result.resize(remove_copy_if_test.size());
    mystl::remove_copy_if(remove_copy_if_test.begin(), remove_copy_if_test.end(),
                        remove_copy_if_result.begin(), uni_operator_bool<vector<int>::value_type>);
    display<vector<int>>(remove_copy_if_result);

    std::cout << "************************test remove_if************************" << std::endl;
    vector<int> remove_if_test = {1, 2, 3, 4, 3, 5, 6, 7, 4, 7, 8, 3};
    vector<int>::iterator remove_if_last = mystl::remove_if(
        remove_if_test.begin(), remove_if_test.end(), uni_operator_bool<vector<int>::value_type>);
    mystl::for_each(remove_if_test.begin(), remove_if_last, print<vector<int>::value_type>);
    cout << endl;

    std::cout << "************************test replace************************" << std::endl;
    vector<int> replace_test = {5, 2, 3, 4, 3, 5, 6, 7, 4, 7, 8, 3};
    mystl::replace(replace_test.begin(), replace_test.end(), 
                    (vector<int>::value_type)(3), (vector<int>::value_type)(999));
    display(replace_test);

    std::cout << "************************test replace_copy************************" << std::endl;
    vector<int> replace_copy_test = {5, 2, 3, 4, 3, 5, 6, 7, 4, 7, 8, 3};
    vector<int> replace_copy_result(replace_copy_test.size());
    mystl::replace_copy(replace_copy_test.begin(), replace_copy_test.end(), replace_copy_result.begin(), 
                        (vector<int>::value_type)(3), (vector<int>::value_type)(999));
    display(replace_copy_test);
    display(replace_copy_result);

    std::cout << "************************test replace_copy_if************************" << std::endl;
    vector<int> replace_copy_if_test = {5, 2, 3, 4, 3, 5, 6, 7, 4, 7, 8, 3};
    vector<int> replace_copy_if_result(replace_copy_test.size());
    mystl::replace_copy_if(replace_copy_if_test.begin(), replace_copy_if_test.end(), replace_copy_if_result.begin(), 
                        uni_operator_bool<vector<int>::value_type>, (vector<int>::value_type)(999));
    display(replace_copy_if_test);
    display(replace_copy_if_result);

    std::cout << "************************test replace_if************************" << std::endl;
    vector<int> replace_if_test = {5, 2, 3, 4, 3, 5, 6, 7, 4, 7, 8, 3};
    mystl::replace_if(replace_if_test.begin(), replace_if_test.end(), 
                            uni_operator_bool<vector<int>::value_type>, (vector<int>::value_type)(999));
    display<vector<int>>(replace_if_test);

    std::cout << "************************test reverse************************" << std::endl;
    vector<int> reverse_test = {1, 2, 3, 4, 5, 6};
    mystl::reverse_dispatch(reverse_test.begin(), reverse_test.end(), mystl::random_access_iterator_tag());
    display<vector<int>>(reverse_test);

    std::cout << "************************test reverse_copy************************" << std::endl;
    vector<int> reverse_copy_test = {1, 2, 3, 4, 5, 6};
    vector<int> reverse_copy_result(reverse_copy_test.size());
    mystl::reverse_copy(reverse_copy_test.begin(), reverse_copy_test.end(), reverse_copy_result.begin());
    display(reverse_copy_test);
    display(reverse_copy_result);

    std::cout << "************************test reverse_copy************************" << std::endl;
    vector<int> random_shuffle_test = {1, 2, 3, 4, 5, 6};
    mystl::random_shuffle(random_shuffle_test.begin(), random_shuffle_test.end());
    display(random_shuffle_test);

    std::cout << "************************test rotate_dispatch************************" << std::endl;
    vector<int> rotate_dispatch_test = {1, 2, 3, 4, 5, 6, 7};
    vector<int>::iterator mid = rotate_dispatch_test.begin() + 2;
    mystl::rotate_dispatch(rotate_dispatch_test.begin(), mid,
                            rotate_dispatch_test.end(), mystl::random_access_iterator_tag());
    display(rotate_dispatch_test);

    std::cout << "************************test partition************************" << std::endl;
    vector<int> partition_test = {2, 2, 2, 2, 1, 1, 1};
    mystl::partition(partition_test.begin(), partition_test.end(), uni_operator_bool<vector<int>::value_type>);
    display(partition_test);

    std::cout << "************************test partition_copy************************" << std::endl;
    vector<int> partition_copy_test = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    vector<int> partition_copy_true(partition_copy_test.size());
    vector<int> partition_copy_false(partition_copy_test.size());
    mystl::partition_copy(partition_copy_test.begin(), partition_copy_test.end(),
                            partition_copy_true.begin(), partition_copy_false.begin(),
                            uni_operator_bool<vector<int>::value_type>);
    display(partition_copy_true);
    display(partition_copy_false);

    std::cout << "************************test sort************************" << std::endl;
    mystl::vector<int> sort_test = { 3, 23, 65, 76, 54, 39, 90, 12, 41, 69 };
    mystl::sort(sort_test.begin(), sort_test.end());
    display<mystl::vector<int>>(sort_test);
    std::cout << sort_test.begin() << std::endl;
}